package edu.cs.usask.ca.silver.plugin.rcp.views.projectviewer;

import org.apache.log4j.Logger;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.Viewer;

import edu.cs.usask.ca.silver.api.persistence.StorageI;
import edu.cs.usask.ca.silver.businesslogic.ids.BaseId;
import edu.cs.usask.ca.silver.businesslogic.ids.ScenarioID;
import edu.cs.usask.ca.silver.businesslogic.ids.UserID;
import edu.cs.usask.ca.silver.plugin.rcp.components.SilverTreeObject;
import edu.cs.usask.ca.silver.plugin.rcp.dao.SilverBusinessLogicController;
import edu.cs.usask.ca.silver.plugin.rcp.jobs.LoggerReportScheduler;

/**
 * The class that is responsible for retrieving the contents from the database
 * that is needed to populate the project viewer structured tree viewer. As the
 * user chooses to expand a branch of the structured tree viewer from in the
 * projects viewer, the needed data is retrieved from the database. The label
 * provider turn this data into a more sensible form.
 * 
 * @author Mike Taylor
 * @author Yudi Xue
 */

public class ProjectViewContentProvider implements ITreeContentProvider {

	private final StorageI storage;
	private final SilverTreeObject root;
	private static Logger logger = Logger
			.getLogger(ProjectViewContentProvider.class);

	public ProjectViewContentProvider(StorageI storage,
			SilverTreeObject treeRoot) {
		this.storage = storage;
		this.root = treeRoot;
	}

	/**
	 * Gets all the children of parentElement
	 * 
	 * @param parentElement
	 *            a TreeObject
	 * @return an array of all the children of parentElement
	 */
	public Object[] getChildren(Object parentElement) {
		if (hasChildren(parentElement)) {
			return getSilverTreeChildrenById((SilverTreeObject) parentElement,
					storage);
		}
		// if the object has no children
		return new Object[0];
	}

	/**
	 * This method take in a Silver TreeObject and call to the Database for an
	 * array or all the children associated with this tree object. This method
	 * call a helper method that creates an array of SilverTreeObjects from
	 * array of Object BaseId that this method obtains.
	 * 
	 * @param silverObject
	 * @return array of silverTreeObject for this silver tree object
	 */
	private SilverTreeObject[] getSilverTreeChildrenById(
			SilverTreeObject silverObject, StorageI storage) {
		BaseId[] objectIds = null;

		// no root is set
		try {
			if (silverObject.getSilverObjectId() != null) {
				objectIds = silverObject.getSilverObjectId()
						.getChildrenObjectIds(storage);
			} else {
				objectIds = SilverBusinessLogicController.borrowUserObject()
						.getAllUserIds(storage);
				SilverBusinessLogicController.returnLastUserObject();
			}
		} catch (NullPointerException e1) {
			LoggerReportScheduler.scheduleErrorLogging(logger,"NullPointer Exception in ProjectViewContentProvider", e1);
		}
		catch (Exception e) {
			LoggerReportScheduler.scheduleErrorLogging(logger,"error in ProjectView", e);
		} finally {
			if (objectIds == null) {
				return null;
			}
		}

		return constructSilverTreeArray(objectIds);
	}/* end of getSilverTreeChildrenById */

	/**
	 * The helper method that convert the array of baseIds into an Array of
	 * SilverTreeObject to be displayed in the project viewer tree structure.
	 * 
	 * @param objectIds
	 * @return array of SilverTreeObject representing the desired level within
	 *         the tree structure THIS CLASS MAY NOT NEED TO DIFFERENTIATE
	 *         BETWEEN TYPE OF BASE IDS
	 */
	private SilverTreeObject[] constructSilverTreeArray(BaseId[] objectIds) {

		BaseId currentId = null;

		/* populating the array of silverTreeObjects for RCP */
		SilverTreeObject resultArray[] = new SilverTreeObject[objectIds.length];
		int i = 0;
		while (i < objectIds.length)
		// while(e.hasMoreElements())
		{

			currentId = objectIds[i];
			try {

				if (currentId.isEntity()) {
					resultArray[i] = new SilverTreeObject(currentId);
				}

			} catch (Exception e) {
				LoggerReportScheduler.scheduleErrorLogging(logger,"error in ProjectView", e);
			}

			/* generic call to database to get this info */
			i++;
		}
		return resultArray;
	}/* end of constructSilverTreeArray */

	/**
	 * Gets the parent of this TreeObject
	 * 
	 * @param element
	 *            a TreeObject
	 * @return the parent of this TreeObject
	 */
	public Object getParent(Object element) {

		assert (element instanceof SilverTreeObject);

		// extracts the unique ID and type of this TreeObject
		if (((SilverTreeObject) element).getSilverObjectId() == null) {
			return null;
		} else if (((SilverTreeObject) element).getSilverObjectId() instanceof UserID) {
			return root;
		}

		BaseId parentId = SilverBusinessLogicController.getParentBaseId(
				((SilverTreeObject) element).getSilverObjectId(), storage);

		return new SilverTreeObject(parentId);
	}

	/**
	 * Determines if a TreeObject has any children
	 * 
	 * @param element
	 *            a TreeObject
	 * @return true if the object has any children, false otherwise
	 */
	public boolean hasChildren(Object element) {
		assert (element instanceof SilverTreeObject);

		// extracts the unique ID and type of this TreeObject
		if (((SilverTreeObject) element).getSilverObjectId() instanceof ScenarioID) {
			return false;
		}
		return true;
	}

	/**
	 * Calls the getChildren method of this class
	 * 
	 * @param inputElement
	 *            a TreeObject
	 * @return an array of all the children of inputElement
	 */
	public Object[] getElements(Object inputElement) {
		return getChildren(inputElement);
	}

	/* ignore these last two for now.... */
	public void dispose() {
	}

	@Override
	public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {

	}

}
